#include "net/timer_queue.h"

#include <time.h>
#include <sys/timerfd.h>

static inline bool TimeSpecIsLess(const struct timespec& ts1,
                                  const struct timespec& ts2) {
  if (ts1.tv_sec < ts2.tv_sec) return false;
  if (ts1.tv_nsec <= ts2.tv_nsec) return false;
  return true;
}

namespace net {
Timer::Timer(Closure* cb, bool is_repeat, int32 delay_sec)
    : delay_(delay_sec), repeat_(is_repeat), cb_(cb) {
  AdjustTime();
}

bool inline Timer::operator <(const struct timespec& ts) const {
  return TimeSpecIsLess(ts_, ts);
}

bool inline Timer::operator <(const struct timespec* ts) const {
  return TimeSpecIsLess(ts_, *ts);
}

bool inline Timer::operator <(const Timer& rhs) const {
  return TimeSpecIsLess(ts_, rhs.ts_);
}

bool inline Timer::operator <(const Timer* rhs) const {
  return TimeSpecIsLess(ts_, rhs->ts_);
}

void Timer::AdjustTime() {
  int ret = ::clock_gettime(CLOCK_REALTIME, &ts_);
  PCHECK(ret != -1) << "clock_gettime error";

  ts_.tv_sec += delay_;
}

TimerQueue::~TimerQueue() {
  poller_->Del(&timer_ev_, EV_READ);
  for (TimerList::iterator it = timer_queue_.begin(); it != timer_queue_.end();
      ++it) {
//   CancleTimer(*it);
    delete *it;
  }
}

void TimerQueue::AddTimer(Timer* const timer) {
  CHECK(timer_fd_ != -1);

  TimerList::iterator it = timer_queue_.begin();
  if (timer_queue_.empty() || *it < timer) {
    timer_queue_.insert(it, timer);
    AdjustTriggerTime();
    return;
  }

  while (it != timer_queue_.end()) {
    if (timer > *it) {
      break;
    }
    ++it;
  }

  timer_queue_.insert(it, timer);
}

void TimerQueue::AddTimerEvent() {
  timer_ev_.fd = timer_fd_;
  timer_ev_.arg = this;
  timer_ev_.cb = TimerQueue::HandleReadEv;
  timer_ev_.event = EV_READ;

  CHECK(poller_->Add(&timer_ev_, EV_READ));
}

void TimerQueue::AdjustTriggerTime() {
  struct itimerspec new_value;
  ::memset(&new_value, 0, sizeof new_value);
  TimerList::iterator it = timer_queue_.begin();
  if (it != timer_queue_.end()) {
    new_value.it_value = (*it)->ts_;
    new_value.it_interval.tv_sec = (*it)->delay_;
  }

  LOG(INFO)<< "adjust time: " << new_value.it_value.tv_sec << " step: " << new_value.it_interval.tv_sec;
  int32 ret = ::timerfd_settime(timer_fd_, TFD_TIMER_ABSTIME, &new_value, NULL);
  PCHECK(ret != -1) << "timerfd_settime error";
}

void TimerQueue::HandleReadEv(int fd, void* arg, int event) {
  TimerQueue* timer_queue = (TimerQueue*) arg;
  int64 val;
  int ret = ::read(fd, &val, sizeof(val));
  if (ret == -1) {
    PLOG(WARNING)<< "timer fd read error, fd: " << fd;
    return;
  }
  LOG(INFO)<< "timer fd read: " << val;
  struct timespec ts;
  ret = ::clock_gettime(CLOCK_REALTIME, &ts);
  PCHECK(ret != -1) << "clock_gettime error";

  timer_queue->CallActiveTimer(ts);
}

void TimerQueue::CallActiveTimer(const struct timespec& ts) {
  TimerList active_timer;
  for (TimerList::iterator it = timer_queue_.begin(); it != timer_queue_.end();
      ++it) {
    Timer* timer = *it;
    LOG(INFO)<< "time: " << ts.tv_sec << " timer: " << timer->ts_.tv_sec << "flag: " << (*timer < ts);
    if (*timer < ts) {
      break;
    }

    active_timer.push_back(timer);
    timer_queue_.erase(it);
    it = timer_queue_.begin();
  }

  for (TimerList::iterator it = active_timer.begin(); it != active_timer.end();
      ++it) {
    scoped_ptr<Timer> timer(*it);
    timer->cb_->Run();

    if (timer->repeat_) {
      timer->AdjustTime();
      AddTimer(timer.release());
    }
  }
}

bool TimerQueue::CreateTimerFd() {
  timer_fd_ = ::timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC);
  if (timer_fd_ == -1) {
    PLOG(WARNING)<< "timerfd_create error";
    return false;
  }

  return true;
}

}
